/*========================================================================
#   FileName: Process.c
#     Author: lwd
#      Email: lwd_xinghuo@126.com
#   HomePage: 
# LastChange: 2013-05-22 15:54:57
#
# implement jobs-queue function
========================================================================*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <malloc.h>
#include "public.h"
#include "Process.h"
#include "Queue.h"
#include "control.h"
#include "sendFile.h"

#if 1
#define PRINT_FUNC() \
	do{\
		printf("FILE:%s FUNC:%s  line:%d\n",\
				__FILE__, __func__, __LINE__);\
	}while(0)
#else
#define PRINT_FUNC() do{}while(0)
#endif

//static gobal variable, only can be used in this file
static LinkQueue lprocess;		//process list
static Process current;			//the current running process

static inline int delete();
static inline int add(Process p);
static        int add_tail();

int init_PQueue()
{
	//init the jobs-queue
	printf("Now, init the process list ...\n");
	delete();
	if(initQueue(&lprocess))
	{
		fprintf(stderr, "init process-list error! func:%s line:%d\n",\
				__func__, __LINE__);
		return 1;
	}
	return 0;
}

Process getCurrentProcess()
{
	return current;
}

static inline int add(Process p)
{
	//add the node p into queue
	int ret;
	ret = EnQueue(&lprocess, p);
	if(ret)
	{
		fprintf(stderr, "EnQueue error!func:%s line:%d\n", \
				__func__, __LINE__);
		return 1;
	}
	else
	{	return 0;	}
}

int add_new(Process p)
{
	//PRINT_FUNC();
	//add a new jobs into jobs-queue
	int ret = 0;
	P();
	ret = add(p);
	V();
	return ret;
}

static int add_tail(int rate)
{
	//PRINT_FUNC();
	//add the current job into queue
	int ret = 1;
	current.state = WAIT;
	current.rate  = rate;
	if(current.pid != -1)
	{
		ret = add(current);
	}
	return ret;
}

int run()
{
	PRINT_FUNC();
	P();
	int ret = 1;
	if(current.pid != -1)
	{
		printf("choose id = %d\n", current.pid);
		ret = kill(current.pid, SIGUSR2);
	}
	V();
	return ret;
}

int pauseCurrent()
{
	int ret = 1;
	P();
	if(current.pid > 0)
	{
		ret = kill(current.pid, SIGUSR1);
		Message msg;
		bzero(&msg, sizeof(msg));
#if 0
		 int ret = recvMSG(&msg);
		 if(!ret)
		 {
		 	printf("recv msg successfully!func:%s line:%d\n",\
						__func__, __LINE__);
		 }
#endif
	}
	V();
	return ret;
}

int stop()
{
	PRINT_FUNC();
	P();
	int ret = 1;
	if(current.pid > 0)		//if current-process is not finished(is exist)
	{
		//send msg to child(pid)
		ret = kill(current.pid, SIGUSR1);
		
		Message msg;
		bzero(&msg, sizeof(msg));
#if 1
		int ret = recvMSG(&msg);
		//int ret = recvMSG();
		//printf("\t\t\tret = %d", ret);
		if(!ret)
		{
			printf("recv msg successfully! func:%s line:%d\n",\
				__func__, __LINE__);
		}
#endif
		//add the current-process into process-list
		sleep(1);
		ret |= add_tail(msg.rate);
	}
	delete();
	V();
	return ret;
}

void *sendfileThread(void* args)
{
	Process* p = (Process*)args;
	printf("pid = %d  jid = %d \n", p->pid, p->jid);
	//求源文件路径
	char desfileName[256];
	char srcfileName[256];
	char tfileName[16];
	bzero(desfileName, 256);
	bzero(srcfileName, 256);
	bzero(tfileName, 16);
	int jid = p->jid;
	int i = 0;
	for(i = 0; i < 15 ; i++)
	{
		//使用进程号的逆序作为文件名
		tfileName[i] = jid%10 + '0';
		jid /= 10;
	}
	strncpy(srcfileName, "./result/", 9);
	strcat(srcfileName, tfileName);
	strncpy(desfileName, p->rsltfile, strlen(p->rsltfile));
	printf("srcfile:%s\ndesfile:%s\n", srcfileName, desfileName);
	free(p);
	int socket = creatConn();
	if(socket < 0)
	{
		fprintf(stderr, "connect to server error! socket = %d\n", socket);
		pthread_exit(0);
	}
	int ret = sendFile(socket, desfileName, srcfileName, jid);
	printf("send file ret:%d\n", ret);
	close(socket);
	pthread_exit(0);
}

static int returnResult()
{
	//保存住 当前值传递到线程中
	Process* temp = (Process*)malloc(sizeof(Process));
	*temp = current;
	pthread_t sf;
	int ret = pthread_create(&sf, NULL, sendfileThread, temp);
	return ret;	
}

int releaseChild()
{
	int status;
	int ret = waitpid(current.pid, &status, 0);
	if(status == 0)
	{
		returnResult();
	}
	delete();
	return ret;
}

int cmp(Process* d1, Process* d2)
{
	return d1->jid == d2->jid;
}

static void testfinished(int sig_num)
{
}

static inline int killProcess(pid_t pid)
{
	signal(SIGCHLD, testfinished);
	int ret = kill(pid, SIGTERM);
	ret |= waitpid(pid, 0, 0);
	return ret;
}

//int deleteFromList(ProcessPtr p)
int deleteFromList(int jid)
{
	//返回0 表示在链表中，返回1 表示没有查找到，
	//返回2表示是当前正在执行进程
	int ret = -2;
	P();
	if(jid == current.jid)
	{
		killProcess(current.pid);
		delete();
		ret = 2;
		printf("kill process:%d\n", current.pid);
	}
	if(ret != 2)
	{
		Process p;
		p.jid = jid;
		ret = DeleteElem(&lprocess, &p, cmp);
		if(!ret)
		{
			killProcess(p.pid);
			printf("kill process:%d\n", p.pid);
		}
	}
	V();
	return ret;
}

int search(ProcessPtr p)
{
	//search a job, return it
	//if cannot find the job,then return 1;
	int ret = 0;
	P();
	if(p->jid == current.jid)
	{
		p->rate = current.rate;
	}
	else
	{
		ret = TravelQueue(lprocess, p, cmp);
	}
	V();
	if(ret)
	{
		return 1; 
	}
	
	return 0;
}

static inline int delete()
{
	//while a job is finished, release its resource, 
	//and delete it from the queue
	//if state = FINISHED,represent the job is delete(finished)
	current.jid = -1;
	current.pid = -1;
	current.state = FINISHED;
	current.rate = 0;
	bzero(&(current.rsltfile), MAXFILENAMESIZE);
	return 0;
}

Process choose_p()
{
	//PRINT_FUNC();
	//choose a job which are ready for running
	Process p = { -1, -1, FINISHED };
	int ret;
	P();
	ret = IsEmpty(lprocess);
	V();
	if(ret)
	{
		return p;
	}
	
	P();
	ret = DeQueue(&lprocess, &p);
	V();
	if(ret)
	{
		fprintf(stderr, "Dequeue error! func:%s line:%d\n",\
				__func__, __LINE__);
		return p;
	}	
	//Dequeue is successful, the choosed process will be running
	P();
	current = p;
	p.state = RUN;
	V();
	return p;
}

int choose()
{
	//choose a job which are ready for running
	Process p = { -1, -1, FINISHED };
	int ret;
	P();
	ret = IsEmpty(lprocess);
	V();
	if(ret)
	{
		return 1;
	}
	
	P();
	ret = DeQueue(&lprocess, &p);
	V();
	if(ret)
	{
		fprintf(stderr, "Dequeue error! func:%s line:%d\n",\
				__func__, __LINE__);
		return 1;
	}
	
	//Dequeue is successful, the choosed process will be runnin
	P();
	current = p;
	p.state = RUN;
	V();
	return 0;
}
